// BMPImage.cpp: implementation of the BMPImage class.
//
//////////////////////////////////////////////////////////////////////

#include "BMPImage.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

BMPImage::BMPImage()
{
zoom = 1.00f;

ww = 0.35;
wh = 0.25;

this->mouseIsOver = 0;
this->isSelected = 0;
}

BMPImage::BMPImage(float x_pos, float y_pos, float x_dim, float y_dim)
{
this->start_x = x_pos;
this->start_y = y_pos;
this->ww = x_dim;
this->wh = y_dim;

zoom = 1.00f;

this->mouseIsOver = 0;
this->isSelected = 0;

widget_x_dim = x_dim;
widget_y_dim = y_dim;
}

BMPImage::BMPImage(float ***m,int h, int w,float x_pos, float y_pos, float x_dim, float y_dim)
{
this->start_x = x_pos;
this->start_y = y_pos;
this->ww = x_dim;
this->wh = y_dim;

zoom = 1.00f;

this->mouseIsOver = 0;
this->isSelected = 0;

widget_x_dim = x_dim;
widget_y_dim = y_dim;

createTexture(m,h,w);
}

BMPImage::~BMPImage()
{
free(this->backImage);
free(this->bits);
free(this->image);
free(this->info);
}

int BMPImage::load(const char *filename)
{
    FILE             *fp;          /* Open file pointer */

	printf("Loading bitmap file %s...\n",filename);

    /* Try opening the file; use "rb" mode to read this *binary* file. */
    if ((fp = fopen(filename, "rb")) == NULL)
        {
        printf("File %s not found...\n",filename);
        return (0); 
        }

    strcpy(this->fileName,filename);

    /* Read the file header and any following bitmap information... */
    if (fread(&header, sizeof(BITMAPFILEHEADER), 1, fp) < 1)
        {
        /* Couldn't read the file header - return NULL... */
		printf("Couldn't read the file header for file : %s\n", filename);
	    fclose(fp);
        return (0);
        }

    if (header.bfType != BF_TYPE)	/* Check for BM reversed... */
        {
        /* Not a bitmap file - return NULL... */
		printf("%s is NOT a bitmap file!\n", filename);
        fclose(fp);
        return (0);
        }

    infosize = header.bfOffBits - sizeof(BITMAPFILEHEADER);
    if ((info = (BITMAPINFO *)malloc(infosize)) == NULL)
        {
        /* Couldn't allocate memory for bitmap info - return NULL... */
		printf("Couldn't allocate memory for bitmap info\n");
        fclose(fp);
        return (0);
        }

    if (fread(info, 1, infosize, fp) < infosize)
        {
        /* Couldn't read the bitmap header - return NULL... */
		printf("Couldn't read the bitmap header for file %s\n", filename);
        free(info);
        fclose(fp);
        return (0);
        }

    /* Now that we have all the header info read in, allocate memory for *
     * the bitmap and read *it* in...                                    */
    if ((bitsize = (info)->bmiHeader.biSizeImage) == 0)
        bitsize = ((info)->bmiHeader.biWidth *
                   (info)->bmiHeader.biBitCount + 7) / 8 *
  	           abs((info)->bmiHeader.biHeight);

    if ((bits = (GLubyte*)malloc(bitsize)) == NULL)
        {
        /* Couldn't allocate memory - return NULL! */
		printf("Couldn't allocate memory for bitmap file %s\n", filename);
        free(info);
        fclose(fp);
        return (0);
        }

    if (fread(bits, 1, bitsize, fp) < bitsize)
        {
        /* Couldn't read bitmap - free memory and return NULL! */
		printf("Couldn't read bitmap\n");
        free(info);
        free(bits);
        fclose(fp);
        return (0);
        }

    /* OK, everything went fine - return the allocated bitmap... */
    fclose(fp);
    createTexture();
    return (1);
}


/*
 * 'SaveDIBitmap()' - Save a DIB/BMP file to disk.
 *
 * Returns 1 on success or 0 on failure...
 */

int BMPImage::save(const char *filename)
    {
    FILE             *fp;          /* Open file pointer */
    GLubyte          *outs;        /* Bytes to be written */

    outs = createPrintableBMP();

    /* Try opening the file; use "wb" mode to write this *binary* file. */
    if ((fp = fopen(filename, "wb")) == NULL)
        return (0);

    /* Figure out the bitmap size */
    if (info->bmiHeader.biSizeImage == 0)
	bitsize = (info->bmiHeader.biWidth *
        	   info->bmiHeader.biBitCount + 7) / 8 *
		  abs(info->bmiHeader.biHeight);
    else
	bitsize = info->bmiHeader.biSizeImage;

    /* Figure out the header size */
    infosize = sizeof(BITMAPINFOHEADER);
    switch (info->bmiHeader.biCompression)
	{
	case BI_BITFIELDS :
            infosize += 12; /* Add 3 RGB doubleword masks */
            if (info->bmiHeader.biClrUsed == 0)
	      break;
	case BI_RGB :
            if (info->bmiHeader.biBitCount > 8 &&
        	info->bmiHeader.biClrUsed == 0)
	      break;
	case BI_RLE8 :
	case BI_RLE4 :
            if (info->bmiHeader.biClrUsed == 0)
              infosize += (1 << info->bmiHeader.biBitCount) * 4;
	    else
              infosize += info->bmiHeader.biClrUsed * 4;
	    break;
	}

    size = sizeof(BITMAPFILEHEADER) + infosize + bitsize;

    /* Write the file header, bitmap information, and bitmap pixel data... */
    header.bfType      = BF_TYPE; /* Non-portable... sigh */
    header.bfSize      = size;
    header.bfReserved1 = 0;
    header.bfReserved2 = 0;
    header.bfOffBits   = sizeof(BITMAPFILEHEADER) + infosize;

    if (fwrite(&header, 1, sizeof(BITMAPFILEHEADER), fp) < sizeof(BITMAPFILEHEADER))
        {
        /* Couldn't write the file header - return... */
        fclose(fp);
        return (0);
        }

    if (fwrite(info, 1, infosize, fp) < infosize)
        {
        /* Couldn't write the bitmap header - return... */
        fclose(fp);
        return (0);
        }

    if (fwrite(outs, 1, bitsize, fp) < bitsize)
        {
        /* Couldn't write the bitmap - return... */
        fclose(fp);
        return (0);
        }

    /* OK, everything went fine - return... */
    fclose(fp);
    free(outs);
    return (1);
}

void BMPImage::print()
{
printf("\n -* BITMAP IMAGE DATA *-\n");
printf("NAME:\t\t\t%s\n",this->fileName);
printf("HEIGHT:\t\t\t%d\n",this->info->bmiHeader.biHeight);
printf("WIDTH:\t\t\t%d\n",this->info->bmiHeader.biWidth);
printf("BIT CNT:\t\t%d\n",this->info->bmiHeader.biBitCount);
printf("BIT CLR IMP:\t\t%d\n",this->info->bmiHeader.biClrImportant);
printf("BIT CLR USED:\t\t%d\n",this->info->bmiHeader.biClrUsed);
printf("BIT COMPRESSION:\t%d\n",this->info->bmiHeader.biCompression);
printf("PLANES:\t\t\t%d\n",this->info->bmiHeader.biPlanes);
printf("SIZE:\t\t\t%d\n",this->info->bmiHeader.biSize);
printf("SIZE IMG:\t\t%d\n",this->info->bmiHeader.biSizeImage);
printf("X PXLS PM:\t\t%d\n",this->info->bmiHeader.biXPelsPerMeter);
printf("Y PXLS PM:\t\t%d\n",this->info->bmiHeader.biYPelsPerMeter);
}

void BMPImage::display()
{
  /*Set up the 2D ambient */
int fh = (float)glutGet ( (GLenum) GLUT_WINDOW_HEIGHT ) ;
int fw = (float)glutGet ( (GLenum) GLUT_WINDOW_WIDTH  ) ;

  glDisable      ( GL_LIGHTING ) ;
  glDisable      ( GL_DEPTH_TEST ) ;
  glDisable      ( GL_CULL_FACE  ) ;

  glEnable       ( GL_ALPHA_TEST ) ;
  glEnable       ( GL_BLEND ) ;
  glAlphaFunc    ( GL_GREATER, 0.1f ) ;
  glBlendFunc    ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
  
  //create an projection that acts like a 2D screen
  glMatrixMode   ( GL_PROJECTION ) ;
  glPushMatrix   () ;
  glLoadIdentity () ;
  glOrtho        ( 0.0, 1.0, 0.0, fw/fh, 0.0, 1.0 ) ;

  glMatrixMode   ( GL_MODELVIEW ) ;
  glPushMatrix   () ;
  glLoadIdentity () ;     
     
   /* Draw border around images */
   float border_x = WIDGET_BORDER_X;
   float border_y = WIDGET_BORDER_Y; 
   
   
   /* Draw and paint map and widget's border when selected or mouse over*/
   if(isSelected)
   {
   glColor4f(WIDGET_SELECTED_COLOR);
   glBegin(GL_QUADS);
   glVertex2f(start_x - border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y - border_y);
   glEnd();
   } 
   else if(mouseIsOver)
   {
   glColor4f(WIDGET_MOUSE_OVER_COLOR);
   glBegin(GL_QUADS);
   glVertex2f(start_x - border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y - border_y);
   glEnd();
   } 

   /* draw default widget border */
   glColor4f(WIDGET_BORDER_COLOR);
   glBegin(GL_LINE_STRIP);
   glVertex2f(start_x - border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y + wh + border_y);
   glVertex2f(start_x + ww + border_x, start_y - border_y);
   glVertex2f(start_x - border_x, start_y - border_y);
   glEnd();
   
   /* Try to calculate the % part of the texture that must appear into the 
   widget... Regarding to screen dimensions, back texture dimensions (power of two)
   image dimensions (h and w). The bigger of the two is forced to 1.0f (I think :-) ) 
   and the smaller is proportioned */
   t_x_dim = screen_x_dim * widget_x_dim * texture_x_dim;
   t_y_dim = screen_y_dim * widget_y_dim * texture_y_dim;
   
   /* The zoom is the same in both directions... fit_dim is used to make vertical
   images as tall as widget and orizontal ones as fat as large as widget.*/
   float xTc = T_start_x;
   float xTd = T_start_x + t_x_dim*zoom*fit_dim;
   float yTc = T_start_y;
   float yTd = T_start_y + t_y_dim*zoom*fit_dim;
   
   // Draw the texture!!!
   glEnable(GL_TEXTURE_2D);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   glBindTexture(GL_TEXTURE_2D, texName);
   glBegin(GL_QUADS);
   glTexCoord2f(xTc, yTc); glVertex2f(start_x, start_y);
   glTexCoord2f(xTc, yTd); glVertex2f(start_x, start_y + wh);
   glTexCoord2f(xTd, yTd); glVertex2f(start_x + ww, start_y + wh);
   glTexCoord2f(xTd, yTc); glVertex2f(start_x + ww, start_y);
   glEnd();
   glDisable(GL_TEXTURE_2D);

 /* Back to 3d view */
	
  glMatrixMode   ( GL_PROJECTION ) ;
  glPopMatrix    () ;
  glMatrixMode   ( GL_MODELVIEW ) ;
  glPopMatrix    () ;
  
  glDisable      ( GL_ALPHA_TEST ) ;
  glDisable      ( GL_BLEND ) ;
  glAlphaFunc    ( GL_ALWAYS, 0.0 ) ;
  glBlendFunc    ( GL_ONE, GL_ZERO ) ;

  glEnable     ( GL_LIGHTING ) ;
  glEnable     ( GL_DEPTH_TEST ) ;
  glEnable      ( GL_CULL_FACE  ) ;
}

int BMPImage::createTexture()
{
int i;
int j;

h = this->info->bmiHeader.biHeight;
w = this->info->bmiHeader.biWidth;

setImageDimensions();
setWidgetDimensions();

bh = getNextPowTwo(h);
bw = getNextPowTwo(w);

setTextureDimensions();
setScreenDimensions();

fitDimensions();

t_x_dim = screen_x_dim * widget_x_dim * texture_x_dim;
t_y_dim = screen_y_dim * widget_y_dim * texture_y_dim;

zoom_x_inc = (1.0 + (ZOOM_FACTOR)/2.0f) - 1.0f;
move_x_inc = ((MOVE_FACTOR + t_x_dim*fit_dim)/(t_x_dim*fit_dim)) - 1.0f;
total_zoom_x_inc = 0.0f;
total_move_x_inc = 0.0f;

//printf("H: %d W: %d BH: %d BW: %d\n",h,w,bh,bw);
//printf("Move inc: %f %f\n",zoom_x_inc,move_x_inc);

/* allocate space for texture */
if( (this->image = (GLubyte*)malloc(h*w*4)) == NULL)
    return 0;
 
if( (this->backImage = (GLubyte*)malloc(bh*bw*4)) == NULL)
    return 0;


int scan_line_completion = 0;
int alpha_scan_line_completionrection = 0;
int zero_padding = w%4;
//printf("zero_padding: %d\n",zero_padding);

for(j = 0; j < h; j++)
     {
     for(i = 0; i < w*3; i += 3)
           {
           // RGB is reversed (BGR), alpha is not present, some zero padding to the
           // end of the scan line to be mult of 4 bytes (R+G+B = 3 bytes) and
           // some other stuff that I won't remember anymore...but now works fine!
           this->image[i+alpha_scan_line_completionrection+2+w*4*j] = (GLubyte)(this->bits[i+0+scan_line_completion+j*w*3]);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           this->image[i+alpha_scan_line_completionrection+1+w*4*j] = (GLubyte)(this->bits[i+1+scan_line_completion+j*w*3]);//printf("[%d %d][%d] %u\n",i,j,i+1+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+1+w*4*j]);
           this->image[i+alpha_scan_line_completionrection+0+w*4*j] = (GLubyte)(this->bits[i+2+scan_line_completion+j*w*3]);//printf("[%d %d][%d] %u\n",i,j,i+2+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+0+w*4*j]);
           this->image[i+alpha_scan_line_completionrection+3+w*4*j] = (GLubyte) 255;                       //printf("[%d %d] [%d] %u\n",i,j,i+3+j*w*4,this->image[i+3+w*4*(h-j-1)]);
           alpha_scan_line_completionrection++;
           }
     scan_line_completion += zero_padding;
     alpha_scan_line_completionrection = 0;
     }

//printf("Gonna create back image...\n");
int i2, j2;
for (i2 = 0; i2 < bh; i2++) {
for (j2 = 0; j2 < bw; j2++) {
backImage[i2+bw*4*j2+0] = (GLubyte) 0;
backImage[i2+bw*4*j2+1] = (GLubyte) 0;
backImage[i2+bw*4*j2+2] = (GLubyte) 0;
backImage[i2+bw*4*j2+3] = (GLubyte) 0;//255
}

}

//printf("Texture map created.\n");

   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glGenTextures(1, &texName);
   glBindTexture(GL_TEXTURE_2D, texName);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bw, bh, 0, GL_RGBA, GL_UNSIGNED_BYTE, backImage);

   glBindTexture(GL_TEXTURE_2D, texName);
   // It should be 0,0 not 1,1... but lines appear... so the texture will
   // be wrong of 1 pixel... but proportions are kept...
   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,w, h, GL_RGBA,GL_UNSIGNED_BYTE, image);

//printf("Texture binded.\n");

   T_start_x = 0.0f;
   T_start_y = 0.0f;

return 1;
}

int BMPImage::getNextPowTwo(int n)
{
    if (n < 4)
       return 4;
    else if (n < 16)
       return 16;
    else if (n < 32)
       return 32;
    else if (n < 64)
       return 64;
    else if (n < 128)
       return 128;
    else if (n < 256)
       return 256;
    else if (n < 512)
       return 512;
    else if (n < 1024)
       return 1024;
    else if (n < 2048)
       return 2048;
    else if (n < 4096)
       return 4096; 
    else if (n < 8192)   
       return 8192;
}

GLubyte* BMPImage::createPrintableBMP()
{
int i,j,k;
int scan_line_completion = 0;
int alpha_scan_line_completionrection = 0;
int zero_padding = w%4;
GLubyte* outbits;

if ((outbits = (GLubyte*)malloc(bitsize)) == NULL)
        {
        return NULL;
        }

/* Zeros in bits */
for(k = 0; k < bitsize; k++)
{
      outbits[k] = (GLubyte)0; //printf("%d\n",k);
}


for(j = 0; j < h; j++)
     {
     for(i = 0; i < w*3; i += 3)
           {
           outbits[i+0+scan_line_completion+j*w*3] = this->image[i+alpha_scan_line_completionrection+2+w*4*j];//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           outbits[i+1+scan_line_completion+j*w*3] = this->image[i+alpha_scan_line_completionrection+1+w*4*j];//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           outbits[i+2+scan_line_completion+j*w*3] = this->image[i+alpha_scan_line_completionrection+0+w*4*j];//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           alpha_scan_line_completionrection++;
           }
     scan_line_completion += zero_padding;
     alpha_scan_line_completionrection = 0;
     }
return outbits;
}
 
void BMPImage::setPosition(float x, float y)
{
     this->start_x = x;
     this->start_y = y;
}

void BMPImage::zoomIn(int z)
{
if(isSelected)
     {
     this->zoom -= ZOOM_FACTOR;
     }
}
 
void BMPImage::zoomOut(int z)
{
if(isSelected)
     {
         this->zoom += ZOOM_FACTOR;
     }
}
 
void BMPImage::moveUp(int u)
{
if(isSelected)
     {
     this->T_start_y += MOVE_FACTOR;
     }
}
 
void BMPImage::moveDown(int d)
{
if(isSelected)
     {
     this->T_start_y -= MOVE_FACTOR;
     }
}
 
void BMPImage::moveLeft(int l)
{
if(isSelected)
     {
     this->T_start_x -= MOVE_FACTOR;
     }
}
 
void BMPImage::moveRight(int r)
{
if(isSelected)
     {
     this->T_start_x += MOVE_FACTOR;
     }
}
 
void BMPImage::mouse(int b, int s, int x, int y)
{
int h = glutGet ( (GLenum) GLUT_WINDOW_HEIGHT ) ;
int w = glutGet ( (GLenum) GLUT_WINDOW_WIDTH  ) ;

float xp = (float)x / (float)w;
float yp = (float)(h-y) / (float)h;

if(w > h)
     {
     xp *= 1.0;
     yp *= 1.0; 
     }
else
    {
    xp *= h/w;
    yp *= 1.0;        
    }

if( (start_x <= xp) &&
    (start_y <= yp) &&
    (xp <= (start_x + ww)) &&
    (yp <= (start_y + wh)) ) //ww and wh should change after resize!!!
    {
    this->mouseIsOver = 1;   
    if( (b == PW_LEFT_BUTTON) && (s == PW_DOWN) )
        {
        if(isSelected){isSelected = 0;} 
        else{isSelected = 1;}
        }
    } 
else
    {
    this->mouseIsOver = 0;
    }
}

void BMPImage::setScreenDimensions()
{
float y = (float)glutGet ( (GLenum) GLUT_SCREEN_HEIGHT ) ;
float x = (float)glutGet ( (GLenum) GLUT_SCREEN_WIDTH  ) ;

if( x > y)             this->screen = HORIZONTAL;
else if (y > x)        this->screen = VERTICAL;
else if (y == x)       this->screen = SQUARED;

//printf("Screen is x: %f y: %f\n",x,y);

if(screen == VERTICAL)
     {
     screen_y_dim = 1.0f;
     screen_x_dim = x / y;
     //printf("Screen VERTICAL.\n");
     }
else if(screen == HORIZONTAL)
     {
     if(imagine == HORIZONTAL)
                {
                screen_x_dim = 1.0f;
                screen_y_dim = x / y;
                }
     else if(imagine == VERTICAL) 
                {
                screen_y_dim = 1.0f;
                screen_x_dim = x / y; 
                }
     else if(imagine == SQUARED)
                {
                screen_y_dim = 1.0f;
                screen_x_dim = x / y;
                }
     //printf("Screen HORIZONTAL.\n");
     }
else if(screen == SQUARED)
     {
     screen_x_dim = 1.0f;
     screen_y_dim = 1.0f;
     //printf("Screen SQUARED.\n");
     }
}

void BMPImage::setTextureDimensions()
{
bh = getNextPowTwo(h);
bw = getNextPowTwo(w);

if( bw > bh)             this->texture = HORIZONTAL;
else if (bh > bw)        this->texture = VERTICAL;
else if (bw == bh)       this->texture = SQUARED;

if(texture == VERTICAL)
     {
     texture_x_dim = (float)w/(float)bw;
     texture_y_dim = (float)w/(float)bw / (bh / bw);
     //printf("Texture VERTICAL.\n");
     }
else if(texture == HORIZONTAL)
     {
     texture_x_dim = (float)h/(float)bh;
     texture_y_dim = (float)h/(float)bh;
     //printf("Texture HORIZONTAL.\n");
     }
else if(texture == SQUARED)
     {
     texture_x_dim = 1.0f;
     texture_y_dim = 1.0f;
     //printf("Texture SQUARED.\n");
     }
     

}

void BMPImage::setImageDimensions()
{
//h = this->info->bmiHeader.biHeight;
//w = this->info->bmiHeader.biWidth;

if( w > h)             this->imagine = HORIZONTAL;
else if (h > w)        this->imagine = VERTICAL;
else if (w == h)       this->imagine = SQUARED;

if(imagine == VERTICAL)
     {
     image_y_dim = 1.0f;
     image_x_dim = (float)w / (float)h; 
     //printf("Image VERTICAL.\n");
     }
else if(imagine == HORIZONTAL)
     {
     image_x_dim = 1.0f;
     image_y_dim = (float)h / (float)w;
     //printf("Image HORIZONTAL.\n");
     }
else if(imagine == SQUARED)
     {
     image_x_dim = 1.0f;
     image_y_dim = 1.0f;
     //printf("Image SQUARED.\n");
     }

}

void BMPImage::setWidgetDimensions()
{

if (ww > wh)              this->widget = HORIZONTAL;
else if (wh > ww)         this->widget = VERTICAL;
else if (ww == wh)        this->widget = SQUARED;

if (widget == VERTICAL)
     {
     if(imagine == HORIZONTAL)
                {
                widget_y_dim = 1.0f;
                widget_x_dim = ww / wh;
                }
     else if(imagine == VERTICAL)
                {
                widget_x_dim = 1.0f;
                widget_y_dim = wh / ww;
                }
     else if(imagine == SQUARED)
                {
                widget_y_dim = 1.0f;
                widget_x_dim = ww / wh;
                }
     //printf("Widget VERTICAL.\n");
     }
else if(widget == HORIZONTAL)
     {
     if(imagine == VERTICAL)
              {
              widget_x_dim = ww / wh;
              widget_y_dim = 1.0f;
              }
     else if(imagine == HORIZONTAL)
              {
              widget_x_dim = 1.0f;
              widget_y_dim = wh/ww;
              }
     else if(imagine == SQUARED)
              {
              widget_x_dim = ww / wh;
              widget_y_dim = 1.0f;
              }
     //printf("Widget HORIZONTAL.\n");
     }
else if(widget == SQUARED)
     {
     widget_x_dim = 1.0f;
     widget_y_dim = 1.0f;
     //printf("Widget SQUARED.\n");
     }
}

void BMPImage::fitDimensions()
{
float tmp_x = screen_x_dim * widget_x_dim  * image_x_dim * texture_x_dim;
float tmp_y = screen_y_dim * widget_y_dim  * image_y_dim * texture_y_dim;

/*printf("screen_x_dim: %f widget_x_dim: %f image_x_dim: %f texture_x_dim: %f \n",screen_x_dim,widget_x_dim,image_x_dim,texture_x_dim);
printf("screen_y_dim: %f widget_y_dim: %f image_y_dim: %f texture_y_dim: %f \n",screen_y_dim,widget_y_dim,image_y_dim,texture_y_dim);
printf("FIT: tmp_x: %f tmp_y: %f\n",tmp_x, tmp_y);*/

if(imagine == VERTICAL)
         {
         fit_dim = (1.0f/tmp_y)*((float)h/(float)bh); 
         }
else if(imagine == HORIZONTAL)
    {
    fit_dim = (1.0f/tmp_x)*((float)w/(float)bw);
    }
else if (imagine == SQUARED)
     {
     fit_dim = (1.0f/tmp_y)*((float)h/(float)bh);
     }
//printf("FIT DIM: %f\n",fit_dim);
//printf("AFTER FT: %f %f\n",tmp_x*fit_dim,tmp_y*fit_dim);
}

int BMPImage::createTexture(float*** m, int he, int wi)
{
int i;
int j;

h = he;
w = wi;

setImageDimensions();
setWidgetDimensions();

bh = getNextPowTwo(h);
bw = getNextPowTwo(w);

setTextureDimensions();
setScreenDimensions();

fitDimensions();

t_x_dim = screen_x_dim * widget_x_dim * texture_x_dim;
t_y_dim = screen_y_dim * widget_y_dim * texture_y_dim;

zoom_x_inc = (1.0 + (ZOOM_FACTOR)/2.0f) - 1.0f;
move_x_inc = ((MOVE_FACTOR + t_x_dim*fit_dim)/(t_x_dim*fit_dim)) - 1.0f;
total_zoom_x_inc = 0.0f;
total_move_x_inc = 0.0f;

printf("H: %d W: %d BH: %d BW: %d\n",h,w,bh,bw);
//printf("Move inc: %f %f\n",zoom_x_inc,move_x_inc);

/* allocate space for texture */
if( (this->image = (GLubyte*)malloc(h*w*4)) == NULL)
    return 0;
 
if( (this->backImage = (GLubyte*)malloc(bh*bw*4)) == NULL)
    return 0;

GLubyte a,b,e,d;

for(j = 0; j < h; j++)
     {
     for(i = 0; i < w; i ++)
           {
           // RGB is reversed (BGR), alpha is not present, some zero padding to the
           // end of the scan line to be mult of 4 bytes (R+G+B = 3 bytes) and
           // some other stuff that I won't remember anymore...but now works fine!
           a=this->image[i+2+w*4*j] = (GLubyte)((m[j][i][0])*255.0f);//printf("[%d %d][%d] %u\n",i,j,i+0+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+2+w*4*j]);
           b=this->image[i+1+w*4*j] = (GLubyte)((m[j][i][1])*255.0f);//printf("[%d %d][%d] %u\n",i,j,i+1+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+1+w*4*j]);
           e=this->image[i+0+w*4*j] = (GLubyte)((m[j][i][2])*255.0f);//printf("[%d %d][%d] %u\n",i,j,i+2+scan_line_completion+j*w*4,this->image[i+alpha_scan_line_completionrection+0+w*4*j]);
           d=this->image[i+3+w*4*j] = (GLubyte)((m[j][i][3])*255.0f);                       //printf("[%d %d] [%d] %u\n",i,j,i+3+j*w*4,this->image[i+3+w*4*(h-j-1)]);
           printf("[%d %d %d %d] ",a,b,e,d);
			}
	 printf("\n");
     }

//printf("Gonna create back image...\n");
int i2, j2;
for (i2 = 0; i2 < bh; i2++) {
for (j2 = 0; j2 < bw; j2++) {
backImage[i2+bw*4*j2+0] = (GLubyte) 0;
backImage[i2+bw*4*j2+1] = (GLubyte) 0;
backImage[i2+bw*4*j2+2] = (GLubyte) 0;
backImage[i2+bw*4*j2+3] = (GLubyte) 255;
}

}

//printf("Texture map created.\n");

   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

   glGenTextures(1, &texName);
   glBindTexture(GL_TEXTURE_2D, texName);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bw, bh, 0, GL_RGBA, GL_UNSIGNED_BYTE, backImage);

   glBindTexture(GL_TEXTURE_2D, texName);
   // It should be 0,0 not 1,1... but lines appear... so the texture will
   // be wrong of 1 pixel... but proportions are kept...
   glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,w, h, GL_RGBA,GL_UNSIGNED_BYTE, image);

//printf("Texture binded.\n");

   T_start_x = 0.0f;
   T_start_y = 0.0f;

return 1;
}

int BMPImage::selected()
{
return isSelected;
}